# @Time : 2024-10-29 9:14
# @Author : Fioman 
# @Phone : 13149920693
"""
生成器是一种特殊的迭代器,它不需要实现__iter__ 和 __next__方法.但是它是不是Iterator类型呢?
所以就引申出另外一个问题,不是所有的迭代器都是Iterator类型的,生成器就不是.但是事实往往是相反的,
我下面的例子证明了一下,生成器确实也是迭代器.
"""
from collections.abc import Iterator


def gen_func():
    yield 1


gen = gen_func()
print(isinstance(gen, Iterator))  # 居然是生成器
print(next(gen))

"""
生成器的实现方式有两种:
1) 带有yield的函数
2) 生成器表达式
生成器有什么特点:
1) 生成器不会一次把所有的元素都加载到内存,而是在调用的时候才生成返回结果.
2) 可以通过for循环进行迭代(因为它也是迭代器)
3) 生成器函数和普通的函数的区别? 生成器有yield关键字,每次调用的时候会返回yield后面的表达式的值,
     并且会记住这个生成器函数的执行位置,下次迭代的时候,从yield的下一条语句开始执行.
4) 通过next(gen) 的方式可以获取生成器的下一条yield的值,for循环执行的时候也是一样的,在遇到StopIteration
     异常的时候结束
"""


# region 生成器函数的执行过程
def gen_function():
    print("第一次yield之前")
    yield "第一次"
    print("第二次yield之前")
    yield "第二次"
    print("第三次yield之前")
    yield "第三次"
    print("第三次yield之后")


gen = gen_function()
print(gen, type(gen), isinstance(gen, Iterator))
print(next(gen))
print(next(gen))
print(next(gen))
try:
    print(next(gen))  # 会捕获到异常,当程序的后面不再有yield的时候出现异常StopIteration异常
except Exception as e:
    print("生成器函数访问结束")
# endregion

# region 2. send() 函数在生成器中的使用.
"""
.send() 和 next() 一样,都能让生成器前进一步(遇到下一个yeild,如果没有下一个yield,都会报StopIteration
异常).
send(value)可以传入一个参数,这个参数是上一次yield表达式的结果.生成器会将接收到值赋值给yield表达式
左边的变量,从而影响生成器的行为.首次启动生成器时,send()参数必须是None,否在会引发异常.
注意send改变的是yield左侧的赋值语句的变量,而不是改变的yield后面的值.
"""


def generator_simple():
    print('启动生成器')
    value = yield "初始化完成"  # 第一次调用生成器的时候,这里的值为None
    # 注意这里的value是None,而不是初始化完成.

    while True:
        print(f"接收到的值为: {value}")
        value = yield value * 2 if value is not None else None  # 将接收到的值乘以2后返回


gen = generator_simple()
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen))

print(gen.send(5))
print(gen.send(10))
print(gen.send(20))

# endregion
